var SkyRTC = function() {
  var PeerConnection = (window.PeerConnection || window.webkitPeerConnection00 || window.webkitRTCPeerConnection || window.mozRTCPeerConnection);
  var URL = (window.URL || window.webkitURL || window.msURL || window.oURL);
  var getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
  var nativeRTCIceCandidate = (window.mozRTCIceCandidate || window.RTCIceCandidate);
  var nativeRTCSessionDescription = (window.mozRTCSessionDescription || window.RTCSessionDescription); // order is very important: "RTCSessionDescription" defined in Nighly but useless
  var moz = !!navigator.mozGetUserMedia;
  var iceServer = {
    "iceServers": [{
      "url": "stun:stun.l.google.com:19302"
    }, {
      "url": "turn:mmt-turn.verkstad.net",
      "username": "webrtc",
      "credential": "secret"
    }]
  };
  var packetSize = 1000;

  /**********************************************************/
  /*                                                        */
  /*                       事件处理器                       */
  /*                                                        */
  /**********************************************************/

  function EventEmitter() {
    this.events = {};
  }
  //绑定事件函数
  EventEmitter.prototype.on = function(eventName, callback) {
    this.events[eventName] = this.events[eventName] || [];
    this.events[eventName].push(callback);
  };
  //触发事件函数
  EventEmitter.prototype.emit = function(eventName, _) {
    var events = this.events[eventName],
      args = Array.prototype.slice.call(arguments, 1),
      i, m;

    if (!events) {
      return;
    }
    for (i = 0, m = events.length; i < m; i++) {
      events[i].apply(null, args);
    }
  };


  /**********************************************************/
  /*                                                        */
  /*                   流及信道建立部分                     */
  /*                                                        */
  /**********************************************************/


  /*******************基础部分*********************/
  function skyrtc() {
    //本地media stream
    this.localMediaStream = null;
    //所在房间
    this.room = "";
    //接收文件时用于暂存接收文件
    this.fileData = {};
    //本地WebSocket连接
    this.socket = null;
    //本地socket的id，由后台服务器创建
    this.me = null;
    //保存所有与本地相连的peer connection， 键为socket id，值为PeerConnection类型
    this.peerConnections = {};
    //保存所有与本地连接的socket的id
    this.connections = [];
    //初始时需要构建链接的数目
    this.numStreams = 0;
    //初始时已经连接的数目
    this.initializedStreams = 0;
    //保存所有的data channel，键为socket id，值通过PeerConnection实例的createChannel创建
    this.dataChannels = {};
    //保存所有发文件的data channel及其发文件状态
    this.fileChannels = {};
    //保存所有接受到的文件
    this.receiveFiles = {};
  }
  //继承自事件处理器，提供绑定事件和触发事件的功能
  skyrtc.prototype = new EventEmitter();

  /*************************服务器连接部分***************************/


  //本地连接信道，信道为websocket
  skyrtc.prototype.connect = function(server, room) {
    var socket,
      rtc = this;
    room = room || "";
    socket = this.socket = io.connect(server);
    //       socket = this.socket = new WebSocket(server);
    /*       socket.on("connect", function(){
            socket.send(JSON.stringify({
                "eventName": "__join",
                "data": {
                    "room": room
                }

            }));

            rtc.emit("socket_opened", socket);
        });
*/

    socket.on("connect", function() {
      socket.emit("__join", room);
      console.log("send join");
      rtc.emit("socket_opened", socket);
    });

    socket.on("message", function(message) {

      var json = JSON.parse(message);
      if (json.eventName) {
        rtc.emit(json.eventName, json.data);
      } else {
        rtc.emit("socket_receive_message", socket, json);
      }

    });

    socket.onerror = function(error) {
      rtc.emit("socket_error", error, socket);
    };

    socket.on("disconnect", function(data) {
      rtc.localMediaStream.close();
      var pcs = rtc.peerConnections;
      for (i = pcs.length; i--;) {
        rtc.closePeerConnection(pcs[i]);
      }
      rtc.peerConnections = [];
      rtc.dataChannels = {};
      rtc.fileChannels = {};
      rtc.connections = [];
      rtc.fileData = {};
      rtc.emit('socket_closed', socket);
    });

    socket.on('_peers', function(connections, myUUID) {
      //获取所有服务器上的
      console.log("peers");
      rtc.connections = connections;
      rtc.me = myUUID;

      rtc.createStream({
        "video": true,
        "audio": true
      });
    });

    socket.on("_ice_candidate", function(data) {
      /*           console.log(data);
                 var json = JSON.parse(data);
                 var data_ = json.data;
      */
      console.log(data);
      var candidate = new nativeRTCIceCandidate(data);
      var pc = rtc.peerConnections[data.socketId];
      pc.addIceCandidate(candidate);
      rtc.emit('get_ice_candidate', candidate);
    });

    socket.on('_new_peer', function(data) {
      rtc.connections.push(data);
      var pc = rtc.createPeerConnection(data),
        i, m;
      pc.addStream(rtc.localMediaStream);
      rtc.emit('new_peer', data);
    });

    socket.on('_remove_peer', function(socketId) {
      var sendId;
      rtc.closePeerConnection(rtc.peerConnections[socketId]);
      delete rtc.peerConnections[socketId];
      delete rtc.dataChannels[socketId];
      for (sendId in rtc.fileChannels[socketId]) {
        rtc.emit("send_file_error", new Error("Connection has been closed"), socketId, sendId, rtc.fileChannels[data.socketId][sendId].file);
      }
      delete rtc.fileChannels[socketId];
      rtc.emit("remove_peer", socketId);
    });

    socket.on('_offer', function(sdp, socketId) {
      rtc.receiveOffer(socketId, sdp);
    });

    socket.on('_answer', function(sdp, socketId) {
      rtc.receiveAnswer(socketId, sdp);
    });
  };

  skyrtc.prototype.ready = function() {
    this.createPeerConnections();
    this.addStreams();
    this.addDataChannels();
    this.sendOffers();
  }


  /*************************流处理部分*******************************/


  //创建本地流
  skyrtc.prototype.createStream = function(options) {
    var rtc = this;

    options.video = !!options.video;
    options.audio = !!options.audio;

    if (getUserMedia) {
      this.numStreams++;
      getUserMedia.call(navigator, options, function(stream) {
          rtc.localMediaStream = stream;
          rtc.initializedStreams++;
          rtc.emit("stream_created", stream);
          if (rtc.initializedStreams === rtc.numStreams) {
            rtc.ready();
          }
        },
        function(error) {
          console.log("stream_create_error");
        });
    } else {
      console.log("stream_create_error" + ':' + 'WebRTC is not yet supported in this browser.');
    }
  };

  //创建
  skyrtc.prototype.createShareStream = function(options) {
    var rtc = this;
    getScreenId(function(error, sourceId, screen_constraints) {
      navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
      navigator.getUserMedia(screen_constraints, function(stream) {
        document.querySelector('video').src = URL.createObjectURL(stream);
        rtc.localMediaStream = stream;
        rtc.initializedStreams++;
        rtc.emit("stream_created", stream);
        if (rtc.initializedStreams === rtc.numStreams) {
          rtc.ready();
        }
      }, function(error) {
        console.error(error);
      });
    });
    var message = "/desktop_share";
    this.broadcast(message);
  };

  //将本地流添加到所有的PeerConnection实例中
  skyrtc.prototype.addStreams = function() {
    var i, m,
      stream,
      connection;
    for (connection in this.peerConnections) {
      this.peerConnections[connection].addStream(this.localMediaStream);
    }
  };

  //将流绑定到video标签上用于输出
  skyrtc.prototype.attachStream = function(stream, domId) {
    var element = document.getElementById(domId);
    if (navigator.mozGetUserMedia) {
      element.mozSrcObject = stream;
      element.play();
    } else {
      element.src = webkitURL.createObjectURL(stream);
    }
    element.src = webkitURL.createObjectURL(stream);
  };


  /***********************信令交换部分*******************************/


  //向所有PeerConnection发送Offer类型信令
  skyrtc.prototype.sendOffers = function() {
    var i, m,
      pc,
      rtc = this,
      pcCreateOfferCbGen = function(pc, socketId) {
        return function(session_desc) {
          pc.setLocalDescription(session_desc);
          console.log(session_desc);
          rtc.socket.emit("__offer", session_desc, socketId);
        };
      },
      pcCreateOfferErrorCb = function(error) {
        console.log(error);
      };
    for (i = 0, m = this.connections.length; i < m; i++) {
      pc = this.peerConnections[this.connections[i]];
      pc.createOffer(pcCreateOfferCbGen(pc, this.connections[i]), pcCreateOfferErrorCb);
    }
  };

  //接收到Offer类型信令后作为回应返回answer类型信令
  skyrtc.prototype.receiveOffer = function(socketId, sdp) {
    var pc = this.peerConnections[socketId];
    pc.setRemoteDescription(new nativeRTCSessionDescription(sdp));
    this.sendAnswer(socketId, sdp);
  };

  //发送answer类型信令
  skyrtc.prototype.sendAnswer = function(socketId, sdp) {
    var pc = this.peerConnections[socketId];
    var rtc = this;
    pc.createAnswer(function(session_desc) {
      pc.setLocalDescription(session_desc);
      rtc.socket.emit("__answer", session_desc, socketId);
    }, function(error) {
      console.log(error);
    });
  };

  //接收到answer类型信令后将对方的session描述写入PeerConnection中
  skyrtc.prototype.receiveAnswer = function(socketId, sdp) {
    var pc = this.peerConnections[socketId];
    pc.setRemoteDescription(new nativeRTCSessionDescription(sdp));
  };

  /***********************点对点连接部分*****************************/


  //创建与其他用户连接的PeerConnections
  skyrtc.prototype.createPeerConnections = function() {
    var i, m;
    for (i = 0, m = this.connections.length; i < m; i++) {
      this.createPeerConnection(this.connections[i]);
    }
  };

  //创建单个PeerConnection
  skyrtc.prototype.createPeerConnection = function(targetSocketId) {
    var rtc = this;
    var pc = new PeerConnection(iceServer);
    this.peerConnections[targetSocketId] = pc;
    pc.onicecandidate = function(evt) {
      if (evt.candidate) {
        rtc.socket.emit("__ice_candidate",evt.candidate.sdpMid, evt.candidate.sdpMLineIndex, evt.candidate.candidate, targetSocketId);
      }
      rtc.emit("pc_get_ice_candidate", evt.candidate, targetSocketId, pc);
    };

    pc.onopen = function() {
      rtc.emit("pc_opened", targetSocketId, pc);
    };

    pc.onaddstream = function(evt) {
      rtc.emit('pc_add_stream', evt.stream, targetSocketId, pc);
    };

    pc.ondatachannel = function(evt) {
      rtc.addDataChannel(targetSocketId, evt.channel);
      rtc.emit('pc_add_data_channel', evt.channel, targetSocketId, pc);
    };
    return pc;
  };

  //关闭PeerConnection连接
  skyrtc.prototype.closePeerConnection = function(pc) {
    if (!pc) return;
    pc.close();
  };


  /***********************数据通道连接部分*****************************/


  //消息广播
  skyrtc.prototype.broadcast = function(message) {
    var socketId;
    for (socketId in this.dataChannels) {
      this.sendMessage(message, socketId);
    }
  };

  //发送消息方法
  skyrtc.prototype.sendMessage = function(message, socketId) {
    if (this.dataChannels[socketId].readyState.toLowerCase() === 'open') {
      this.dataChannels[socketId].send(JSON.stringify({
        type: "__msg",
        data: message
      }));
    }
  };

  //对所有的PeerConnections创建Data channel
  skyrtc.prototype.addDataChannels = function() {
    var connection;
    for (connection in this.peerConnections) {
      this.createDataChannel(connection);
    }
  };

  //对某一个PeerConnection创建Data channel
  skyrtc.prototype.createDataChannel = function(socketId, label) {
    var pc, key, channel;
    pc = this.peerConnections[socketId];

    if (!socketId) {
      this.emit("data_channel_create_error", socketId, new Error("attempt to create data channel without socket id"));
    }

    if (!(pc instanceof PeerConnection)) {
      this.emit("data_channel_create_error", socketId, new Error("attempt to create data channel without peerConnection"));
    }
    try {
      channel = pc.createDataChannel(label);
    } catch (error) {
      this.emit("data_channel_create_error", socketId, error);
    }

    return this.addDataChannel(socketId, channel);
  };

  //为Data channel绑定相应的事件回调函数
  skyrtc.prototype.addDataChannel = function(socketId, channel) {
    var rtc = this;
    channel.onopen = function() {
      rtc.emit('data_channel_opened', channel, socketId);
    };

    channel.onclose = function(event) {
      delete rtc.dataChannels[socketId];
      rtc.emit('data_channel_closed', channel, socketId);
    };

    channel.onmessage = function(message) {
      var json;
      json = JSON.parse(message.data);
      if (json.type === '__file') {
        /*rtc.receiveFileChunk(json);*/
        rtc.parseFilePacket(json, socketId);
      } else {
        rtc.emit('data_channel_message', channel, socketId, json.data);
      }
    };

    channel.onerror = function(err) {
      rtc.emit('data_channel_error', channel, socketId, err);
    };

    this.dataChannels[socketId] = channel;
    return channel;
  };

  return new skyrtc();
};
